Dataset Earthquakes historical data from 1800 to 2021¶

## Introduzione: La presente documentazione si propone di fornire una trattazione esaustiva del nostro dataset inerente gli eventi sismici, un corpus di dati che spazia dal 1800 al 2021. Il nostro intento è presentare una disamina metodica e organizzata delle caratteristiche fondamentali di questo dataset, illustrandone la struttura e sottolineando le potenzialità di analisi intrinseche nel contesto degli eventi sismici. Abbiamo inizialmente adottato come nostro dataset di base una raccolta dettagliata di informazioni sugli eventi sismici e i disastri associati, verificatisi in varie parti del globo. La sua vasta portata temporale, estendendosi dal 1800 al 2021, ci ha fornito una ricca varietà di dati, che spaziano dai dettagli temporali e geografici agli impatti derivanti da ciascun evento. Tuttavia, constatando la limitatezza di alcune informazioni nel dataset principale, abbiamo intrapreso l'iniziativa di ampliarlo integrando due dataset supplementari che trattano la medesima tematica. Questo approccio strategico mira a colmare le lacune informative, consentendoci di ottenere una visione più completa e dettagliata. Attraverso l'incorporazione dei nuovi dati, miriamo a esplorare in modo più approfondito e accurato la complessità dei fenomeni sismici e dei disastri associati.
#### Definizione di terremoto Prima di passare alla descrizione del nostro dataset è necessario dare una panoramica di quella che è la definizione di terremoto. Una scossa tellurica, comunemente chiamata terremoto o sisma, è un fenomeno geofisico caratterizzato da una rapida liberazione di energia sotto forma di onde sismiche, che si propagano attraverso la Terra. Questo fenomeno è causato principalmente dal rilascio di tensione accumulata lungo faglie o region di frattura all'interno della litosfera terrestre. Quando le rocce lungo una faglia subiscono una deformazione e raggiungono un punto in cui non possono più sostenere los angeles tensione accumulata, si verifica una rottura improvvisa. Questo processo rilascia una considerevole quantità di energia sotto forma di onde sismiche, che si diffondono radialmente dalla zona di rottura, nota come ipocentro o focolare del terremoto. Le scosse telluriche possono variare notevolmente in intensità, dalla percezione appena avvertibile a eventi distruttivi su vasta scala. La scala più comunemente utilizzata in step with misurare l'intensità di un terremoto è la Scala di magnitudo di momento sismico (scala Richter), che assegna un valore numerico al terremoto in base all'energia rilasciata. Le conseguenze di una scossa tellurica dipendono da diversi fattori, tra cui la Magnitudo del terremoto, la Profondità dell'ipocentro, los angeles distanza dal centro urbano e la Qualità delle strutture edilizie presenti nella zona colpita.
### Principali caratteristiche dei dataset: #### Primo dataset: Il dataset da noi scelto contiene informazioni dal 1800 al 2021. Le colonne presenti sono 38 per un totale di 4823 righe. Ogni evento è rappresentato da un terremoto. Di seguito sono elencate alcuni dettagli del nostro dataset. **Informazioni Temporali:** Il dataset include informazioni sulla data e l'orario di ciascun evento sismico, consentendo di analizzare la distribuzione temporale di tali incidenti nel corso degli anni. **Dettagli Geografici:** Le coordinate geografiche (latitudine e longitudine) forniscono informazioni sulla posizione precisa di ogni evento sismico, consentendo l'analisi della distribuzione geografica e l'identificazione di regioni più suscettibili. **Intensità Sismica:** La magnitudo sismica (colonna 'Mag') fornisce una stima dell'intensità di ciascun evento, permettendo di classificarli in base alla loro forza. **Impatti Associati:** Diverse colonne forniscono dettagli sugli impatti dei terremoti, inclusi il numero totale di vittime, i danni materiali, il numero di edifici distrutti o danneggiati, e altre informazioni correlate. **Descrizioni Aggiuntive:** Alcune colonne contengono descrizioni aggiuntive, come la tipologia di danno (es. danni finanziari), le caratteristiche degli eventi, e le circostanze specifiche in cui si sono verificati.
#### Secondo Dataset: Come secondo dataset abbiamo **Informazioni Temporali:** Le colonne 'Year', 'Mo' (mese), 'Dy' (giorno), 'Hr' (ora), 'Mn' (minuto) e 'Sec' (secondo) forniscono dettagli temporali sugli eventi. **Localizzazione Geografica:** Le colonne 'Location Name', 'Latitude', e 'Longitude' forniscono informazioni sulla posizione geografica degli eventi sismici. **Intensità Sismica:** La colonna 'Mag' rappresenta la magnitudo sismica, che fornisce un'indicazione dell'intensità dell'evento. **Impatti Associati:** Diverse colonne forniscono dettagli sugli impatti degli eventi, inclusi il numero totale di vittime, danni materiali (rappresentati in dollari), il numero di edifici distrutti o danneggiati, e altre informazioni correlate. Tsunami e Attività Vulcanica: Le colonne 'Tsu' e 'Vol' indicano la presenza di tsunami e attività vulcanica associata agli eventi. Il dataset presenta varie colonne che forniscono dettagli specifici sugli impatti sociali ed economici degli eventi, tra cui feriti, morti, danni finanziari e danni strutturali.
#### Terzo Dataset: Il dataset sugli terremoti (1990-2023) rappresenta un ampio archivio di informazioni riguardanti tutti i terremoti registrati nel mondo nel periodo indicato. Con circa tre milioni di righe, ogni riga corrisponde a un evento sismico specifico. Le colonne del dataset contengono attributi rilevanti relativi a ciascun terremoto, tra cui data e ora dell'evento, posizione geografica (latitudine e longitudine), magnitudo, profondità dell'epicentro, tipo di magnitudo utilizzata, regione interessata e altre informazioni pertinenti. Le principali colonne includono il timestamp dell'evento, il luogo in cui è avvenuto, lo stato dell'evento, l'indicazione se ha generato uno tsunami, la sua significatività, il tipo di dati associati, la magnitudo, lo stato, le coordinate geografiche, la profondità e la data dell'evento ### Potenziale: Questo dataset offre l'opportunità di condurre analisi approfondite sugli eventi sismici nel corso del tempo e delle loro conseguenze. Possibili aree di indagine includono la correlazione tra la magnitudo sismica e l'entità degli impatti, l'identificazione di regioni ad alto rischio sismico, e l'analisi di tendenze temporali nei disastri associati ai terremoti.

Set-Up generale:¶

Operazioni preliminari che ci hanno permesso di lavorare con il dataset sono state:

  • Creazione di una colonna Date che raggruppa le colonne Year, Month, Day, Hour, Minute, Second.
  • Rimuovere la colonna chiamata 'I_D' dal DataFrame.
  • Unione dei tre dataset in modo da avere più dati:
    • Il primo e il secondo dataset vengono uniti mediante concatenazione, mantenendo la struttura e le colonne presenti nel primo dataset. La concatenazione avviene verificando l'esistenza dei terremoti nel dataset di partenza, in maniera da poter evitare la ripetizione dello stesso evento. Due terremoti vengono considerati lo stesso evento quando presentano Date, Longitude e Latitude uguali. Ciò permette di aggiungere svariate righe al dataset utilizzato per le analisi, mantenendo però la struttura del dataset originale.
    • Il terzo dataset invece contiene diverse colonne interessanti come le varie magnitudini fornite in diverse scale e unità di misura che vogliamo integrare all'interno del dataset preso in analisi. È stato dunque eseguito un merge dei dataset in modalità 'left', ovvero mantenendo la struttura di partenza del dataset utilizzato e aggiungendoci le colonne del terzo dataset qui fornite:
      • Eq Mag Ms: Scala di magnitudo delle onde di superficie
      • Eq Mag Mw: Scala di magnitudo del momento sismico
      • Eq Mag Mb: Scala di magnitudo dell'onda corporea
      • Eq Mag Mfa: Scala di magnitudo macrosismica
      • Eq Mag Unk: Scala di magnitudo sconosciuta, dunque generica e approssimata
      • Country: Il paese colpito all'epicentro del terremoto
      • Region Code: Codice con cui viene indicata la regione colpita
      • State: Lo stato colpito all'epicentro del terremoto
    • Inoltre viene effettuata una concatenazione anche con il terzo dataset in modo da aggiungere al dataset analizzato i terremoti in esso presenti ma assenti nell'oggetto preso in analisi. La concatenazione qui effettuata viene applicata allo stesso modo della concatenazione tra primo e secondo dataset.
  • Sostituire i caratteri di sottolineatura nelle intestazioni delle colonne con spazi vuoti e convertire la prima lettera di ogni parola in maiuscolo.
  • Convertire tutte le intestazioni delle colonne in maiuscolo.
  • Rinominare alcune colonne specifiche
  • Trasformare una lista di colonne ('Sec', 'Longitude', 'Latitude') che devono essere convertite in numeri.
In [1]:
# Import delle librerie

#import for Numpy
import numpy as np

#import for Plotly
import plotly.express as px
import plotly.graph_objects as go

#import for Pandas
import pandas as pd

from datetime import datetime
In [2]:
df_earthQuake = pd.read_csv("data/EarthQuake/Earthquakes historical data from 1800 to 2021.csv")
df_toMerge1 = pd.read_csv("data/EarthQuake/earthquakes_secondCSV.csv")
df_toMerge2 = pd.read_csv("data/EarthQuake/Worldwide-Earthquake-database.csv")

Aggiunta della colonna Date¶

La funzione add_date_col accetta un DataFrame contenente colonne separate per anno, mese, giorno e tempo. Crea una nuova colonna 'Date' combinando queste informazioni, gestisce le conversioni di tipo e aggiunge eventuali offset di tempo definiti nelle colonne di ora, minuto e secondo. Infine, elimina le righe con date mancanti e colonne non necessarie, restituendo il DataFrame modificato.

In [3]:
def add_date_col(df_passed):
    main_cols = ['Year', 'Mo', 'Dy']
    add_cols = ['Hr', 'Mn', 'Sec']

    df = df_passed.dropna(subset=main_cols).copy()

    for col in main_cols:
        df[col] = df[col].astype(int).astype(str)

    df[main_cols[-2:]] = df[main_cols[-2:]].apply(lambda col: col.apply(lambda x: str(x).zfill(2)))

    df['Date'] = df[main_cols].agg('-'.join, axis=1)
    df['Date'] = pd.to_datetime(df['Date'], format='%Y-%m-%d', errors='coerce')
    df = df[['Date'] + [col for col in df.columns if col != 'Date']]

    valid_time = df[add_cols].notna().any(axis=1)

    for col in add_cols:
        df[col] = df[col].apply(lambda x: str(int(round(x))) if pd.notna(x) else '00').str.zfill(2)

    time_delta_str = df.loc[valid_time, add_cols].agg(':'.join, axis=1)
    time_delta = pd.to_timedelta(time_delta_str, errors='coerce')

    df.loc[valid_time, 'Date'] += time_delta
    df.dropna(subset=['Date'], inplace=True)
    df.drop(main_cols+add_cols, axis=1, inplace=True)
    return df

La funzione clean_dataset effettua una serie di operazioni di pulizia su un DataFrame. Rimuove una colonna specifica, normalizza i nomi delle colonne, rinomina alcune colonne per chiarezza, e converte alcune colonne in formato numerico. In particolare, gestisce la colonna 'Tsu' trasformando i valori 'Yes' in 1 e 'No' in 0, e converte le colonne 'Sec', 'Longitude' e 'Latitude' in numeri, trattando eventuali errori di conversione. Il DataFrame risultante è più pulito e pronto per il merging e per ulteriori analisi.

In [4]:
def clean_dataset(df):
    df.drop('I_D', axis=1, inplace=True)
    df.columns = [col.replace('_', ' ').title() for col in df.columns]
    df.columns = [col.title() for col in df.columns]
    df.rename(columns={
        'Month':'Mo', 'Day':'Dy', 'Hour':'Hr', 'Minute':'Mn', 'Second':'Sec', 'Focal Depth':'Focal Depth (km)',
        'Total Deaths Description':'Total Death Description', 'Deaths Description':'Death Description',
        'Total Damage Millions Dollars':'Total Damage ($Mil)', 'Damage Millions Dollars':'Damage ($Mil)',
        'Flag Tsunami':'Tsu', 'Eq Primary':'Mag', 'Intensity':'MMI Int'
    }, inplace=True)
    col_to_convert = ['Sec','Longitude', 'Latitude']
    df[col_to_convert] = df[col_to_convert].apply(pd.to_numeric, errors='coerce')

    df['Tsu'] = df['Tsu'].replace({'Yes':1, 'No':0}).astype(float)
    return df
In [5]:
df_toMerge2 = clean_dataset(df_toMerge2)

df_cleaned1 = add_date_col(df_earthQuake)
df_cleaned2 = add_date_col(df_toMerge1)
df_cleaned3 = add_date_col(df_toMerge2)

Procediamo con l'unione dei tre DataFrames (df_cleaned1, df_cleaned2, e df_cleaned3) al fine di costituire un nuovo DataFrame denominato "dataset_combinato". Questo insieme di dati aggregato è caratterizzato dall'assenza di duplicati riscontrati nelle colonne 'Date', 'Longitude' e 'Latitude'.

Successivamente, generiamo un DataFrame denominato "df_merged" attraverso l'operazione di fusione tra "dataset_combinato" e una selezione specifica di colonne provenienti da "df_cleaned3". Tale operazione di fusione si basa sulle colonne 'Date', 'Longitude', e 'Latitude', e si concretizza mantenendo integralmente tutte le righe provenienti da "dataset_combinato".

Successivamente, procediamo all'eliminazione dei duplicati basati sulle colonne 'Date', 'Longitude', e 'Latitude'. Il DataFrame risultante, df_merged, viene ordinato in base alla colonna 'Date'. Infine, le righe contenenti valori mancanti nella colonna 'Mag' vengono diligentemente rimosse dal dataset risultante.

In [6]:
dataset_combinato = pd.concat([df_cleaned1, df_cleaned2], ignore_index=True).drop_duplicates(subset=['Date','Longitude','Latitude'])

df3_columns = ['Date', 'Longitude', 'Latitude', 'Eq Mag Ms', 'Eq Mag Unk', 'Eq Mag Mw', 'Eq Mag Mb', 'Country', 'Eq Mag Mfa', 'Region Code', 'State']

df_merged = pd.merge(dataset_combinato,
                     df_cleaned3[df3_columns],
                     left_on=['Date', 'Longitude', 'Latitude'],
                     right_on=['Date', 'Longitude', 'Latitude'],
                     how='left')

df_merged = pd.concat([df_merged, df_cleaned3], ignore_index=True).drop_duplicates(subset=['Date','Longitude','Latitude'])
df_merged = df_merged.sort_values(by='Date')
df_merged = df_merged.reset_index(drop=True)
df_merged = df_merged.dropna(subset=['Mag'])

Qui di seguito é possibile visionare tutte le colonne presenti nel dataset e i loro tipi

In [7]:
df_merged.dtypes
Out[7]:
Date                                  datetime64[ns]
Tsu                                          float64
Vol                                          float64
Location Name                                 object
Latitude                                     float64
Longitude                                    float64
Focal Depth (km)                             float64
Mag                                          float64
MMI Int                                      float64
Deaths                                       float64
Death Description                            float64
Missing                                      float64
Missing Description                          float64
Injuries                                     float64
Injuries Description                         float64
Damage ($Mil)                                float64
Damage Description                           float64
Houses Destroyed                             float64
Houses Destroyed Description                 float64
Houses Damaged                               float64
Houses Damaged Description                   float64
Total Deaths                                 float64
Total Death Description                      float64
Total Missing                                float64
Total Missing Description                    float64
Total Injuries                               float64
Total Injuries Description                   float64
Total Damage ($Mil)                          float64
Total Damage Description                     float64
Total Houses Destroyed                       float64
Total Houses Destroyed Description           float64
Total Houses Damaged                         float64
Total Houses Damaged Description             float64
Eq Mag Ms                                    float64
Eq Mag Unk                                   float64
Eq Mag Mw                                    float64
Eq Mag Mb                                    float64
Country                                       object
Eq Mag Mfa                                   float64
Region Code                                  float64
State                                         object
Eq Mag Ml                                    float64
dtype: object

Il dataset parsato e pulito alla fine risulta come segue:

In [8]:
df_merged
Out[8]:
Date Tsu Vol Location Name Latitude Longitude Focal Depth (km) Mag MMI Int Deaths ... Total Houses Damaged Description Eq Mag Ms Eq Mag Unk Eq Mag Mw Eq Mag Mb Country Eq Mag Mfa Region Code State Eq Mag Ml
0 1677-11-04 00:00:00 322.0 NaN JAPAN: OFF SE. BOSO PENINSULA 35.000 141.500 NaN 7.4 NaN NaN ... NaN 7.4 NaN NaN NaN JAPAN NaN 30.0 NaN NaN
5 1678-06-18 01:45:00 325.0 NaN PERU: LIMA,SALINAS-HUAURA,LIMA,CALLAO,CHANCAY -9.000 -79.000 40.0 8.4 9.0 NaN ... NaN 8.4 NaN NaN NaN PERU NaN 160.0 NaN NaN
6 1678-10-02 00:00:00 NaN NaN JAPAN: SANRIKU,RIKUCHU 38.600 142.000 NaN 7.4 NaN 1.0 ... NaN NaN 7.4 NaN NaN JAPAN NaN 30.0 NaN NaN
7 1679-06-04 00:00:00 NaN NaN TURKEY; ARMENIA: DVINA 40.100 44.700 15.0 5.9 NaN 7600.0 ... NaN NaN 5.9 NaN NaN TURKEY NaN 140.0 NaN NaN
8 1679-09-02 00:00:00 NaN NaN CHINA: HEBEI PROVINCE 40.000 117.000 NaN 8.0 11.0 13162.0 ... NaN 8.0 NaN NaN NaN CHINA NaN 30.0 NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
5467 2023-01-28 18:14:45 NaN NaN IRAN: KHVOY (KHOY) 38.424 44.909 16.0 5.9 8.0 3.0 ... 4.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
5468 2023-02-06 01:17:35 5873.0 NaN TURKEY; SYRIA 37.166 37.042 17.0 7.8 9.0 48224.0 ... 4.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
5469 2023-02-06 10:24:49 NaN NaN TURKEY; SYRIA 38.024 37.203 10.0 7.5 9.0 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5470 2023-02-09 06:28:00 NaN NaN INDONESIA: NEW GUINEA: IRIAN JAYA: JAYAPURA -2.635 140.557 22.0 5.1 8.0 4.0 ... 1.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
5471 2023-02-20 17:04:29 NaN NaN TURKEY; SYRIA 36.109 36.017 16.0 6.3 9.0 6.0 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

4416 rows × 42 columns

Distribuzione temporale degli eventi sismici¶

Il grafico sottostante mostra la dispersione della distribuzione temporale degli eventi sismici.

Ogni punto nel grafico corrisponde al conteggio del numero di terremoti avvenuti prima e durante la data fornita. La dispersione dei punti sulla trama fornisce una rappresentazione visiva della distribuzione degli eventi nel tempo

Questo grafico fornisce una visione immediata della distribuzione temporale degli eventi sismici, consentendo all'utente di identificare trend o periodi di maggiore attività sismici

In [9]:
# Crea un grafico a dispersione con Plotly Express
fig = px.scatter(df_merged, x='Date', y=df_merged.index, 
                 title='Distribuzione Temporale degli Eventi Sismici',
                 labels={'index': 'Somma del numero di Eventi', 'Date': 'Data'})
fig.update_traces(marker=dict(size=5, opacity=0.5))
fig.update_layout(
    xaxis=dict(showline=True, linewidth=2, linecolor='black'),
    yaxis=dict(showline=True, linewidth=2, linecolor='black'),
    showlegend=False, height=600, width=1000)
# Mostra il grafico
fig.show()

Il prossimo grafico mostra la distribuzione temporale (annuale) degli eventi sismici.

Ogni punto nel grafico corrisponde al conteggio del numero di terremoti avvenuti nell'anno fornito. Come il grafico precedente, anche questo fornisce la dispersione dei punti sulla trama e fornisce una rappresentazione visiva della distribuzione degli eventi nel tempo

Tramite esso è notabile come all'avanzare degli anni, aumenti anche il numero di terremoti registrati ogni anno. Crediamo che ciò sia dovuto al progressivo miglioramento della precisione appartenente alle tecnologie di registrazione dei sismi. Queste tecnologie, aumentando la precisione, possono rilevare eventi con sempre meno magnitudine che probabilmente qualche anno prima non sarebbe stato rilevato.

In [10]:
df_merged['Year'] = pd.to_datetime(df_merged['Date']).dt.year
df_grouped = df_merged.groupby('Year').size().reset_index(name='Earthquakes')

# Crea il grafico con Plotly Express
fig = px.bar(df_grouped, x='Year', y='Earthquakes', labels={'Earthquakes': 'Numero di Terremoti'})
fig.update_layout(
    title='Distribuzione del numero di Terremoti per Anno', 
    xaxis_title='Anno', 
    yaxis_title='Numero di Terremoti',
    height=600, width=1000)

# Mostra il grafico
fig.show()

Numero annuo di Morti causa terremoto¶

Analizziamo il numero annuale di decessi causati da eventi sismici mediante un grafico che illustra la relazione tra le morti e gli anni. A tal fine, abbiamo effettuato una suddivisione dei dati in base agli anni e calcolato la somma dei decessi per ciascun anno.

Il grafico presenta una linea che indica la media annuale dei decessi, accompagnata da un'annotazione che fornisce il valore medio. Tale rappresentazione visiva consente di comprenderne la variazione annuale e di confrontare ogni anno rispetto alla media.

In [11]:
earthquake_data = pd.DataFrame({
    'Deaths': df_merged['Deaths'],
    'Year': df_merged['Date'].dt.year
})

# Group by year and sum the deaths for each year
deaths_per_year = earthquake_data.groupby('Year')['Deaths'].sum().reset_index()

# Calculate the average number of deaths per year
average_deaths_per_year = deaths_per_year['Deaths'].mean()

# Create a line plot using plotly.express
fig = px.line(deaths_per_year, x='Year', y='Deaths',
              title='Numero di morti a causa di terremoti ogni anno',
              labels={'Deaths': 'Numero di morti', 'Year': 'Anno'},
              template='plotly')

# Add a horizontal line for the average
fig.add_shape(type='line',
              x0=deaths_per_year['Year'].min(),
              x1=deaths_per_year['Year'].max(),
              y0=average_deaths_per_year,
              y1=average_deaths_per_year,
              line=dict(color='red', dash='dash')
              )

fig.add_annotation(
    x=deaths_per_year['Year'].min()+50,
    y=average_deaths_per_year-10,
    text=f'In media: {average_deaths_per_year:.2f} morti all\'anno',
    font=dict(size=14),
    showarrow=True,
    arrowhead=2,
    ax=50,
    ay=-120
)

fig.update_layout(
    xaxis=dict(showline=True, linewidth=2, linecolor='black'),
    yaxis=dict(showline=True, linewidth=2, linecolor='black'),
    showlegend=False, height=700, width=1100
)

fig.update_yaxes(range=[0,deaths_per_year['Deaths'].max()])

# Show the graph
fig.show()

Distribuzione geografica degli eventi sismici¶

Abbiamo prodotto tre visualizzazioni grafiche per delineare la distribuzione degli eventi sismici.

La prima rappresentazione consiste in una mappa geografica del pianeta Terra, in cui ogni punto rappresenta un singolo evento sismico. La gradazione di tonalità attribuita ai punti è direttamente proporzionale al valore della magnitudo registrata, manifestando un rapporto inversamente proporzionale tra la chiarezza del colore e l'entità della magnitudo. Punti più scuri corrispondono a magnitudini più elevate, mentre punti più chiari indicano magnitudini inferiori.

La seconda rappresentazione consiste in una HeatMap, che visualizza la densità degli eventi sismici in un contesto spaziale. Tale rappresentazione grafica offre una percezione immediata delle regioni con maggiore concentrazione di attività sismica.

Infine, la terza rappresentazione consiste in una breve animazione temporale che illustra l'evoluzione degli eventi sismici nel corso del tempo. Questa dinamica visualizzazione offre un'opportunità unica di esaminare la distribuzione temporale degli eventi sismici, consentendo l'osservazione di eventuali pattern o variazioni nel corso del tempo.

In [12]:
df = df_merged.dropna(subset=['Latitude', 'Longitude', 'Mag'], inplace=False)
fig = px.scatter_geo(df, lat='Latitude', lon='Longitude',
                     title='Distribuzione Geografica degli Eventi Sismici',
                     labels={'Latitude': 'Latitudine', 'Longitude': 'Longitudine', 'Mag':'Magnitudine'},
                     hover_name='Location Name',
                     color_continuous_scale=px.colors.sequential.Reds,
                     projection='natural earth', 
                     color='Mag',  
                     opacity=0.7)  

fig.update_layout(geo=dict(projection_scale=1, center=dict(lat=0, lon=0)))
fig.update_layout(height=600, width=1000)
fig.show()

Il codice sottostante genera una heatmap che mostra la distribuzione geografica degli eventi sismici. Inizialmente vengono calcolati i valori minimi e massimi delle latitudini e longitudini presenti nel dataset. Successivamente viene creata la mappa e vengono inseriti i dati calcolati.

È interessante notare che la maggior parte degli eventi si verifica sulle coste. Questo è dovuto alla tectonica delle placche e alla presenza di limiti di placca lungo i margini delle masse continentali. Infatti le regioni costiere spesso si trovano vicino ai confini delle placche tettoniche. Questi sono luoghi in cui le placche litosferiche della crosta terrestre interagiscono. Gli eventi sismici sono spesso il risultato della liberazione di energia durante i movimenti delle placche, che possono portare a deformazioni della crosta terrestre e alla formazione di faglie.

Inoltre queste regioni sono influenzate dalla subduzione, un processo in cui una placca litosferica scivola sotto un'altra placca. Questo fenomeno può causare terremoti di grandi dimensioni e anche generare vulcani nelle regioni costiere.

In [13]:
lat_min, lat_max = df_merged['Latitude'].min(), df_merged['Latitude'].max()
lon_min, lon_max = df_merged['Longitude'].min(), df_merged['Longitude'].max()
center_lat = (lat_min + lat_max) / 2
center_lon = (lon_min + lon_max) / 2

fig = px.density_mapbox(df_merged, lat='Latitude', lon='Longitude',
                        title='Heatmap della Distribuzione Geografica degli Eventi Sismici',
                        mapbox_style='carto-positron',
                        color_continuous_scale=px.colors.sequential.Reds,
                        opacity=0.7, radius=3, zoom=0.9,
                        center=dict(lat=center_lat+25, lon=center_lon+25))

fig.update_layout(
    margin=dict(l=10, r=10, b=10, t=60),
    height=600,
    width=1000,
    coloraxis_colorbar=dict(title='Densità')
)
fig.show()

Come ultimo grafico per la distribuzione geografica abbiamo generato un animazione. Questa mostra tutti gli eventi sismici dal 1800 al 2023 presenti in tutto il mondo.

In [14]:
df_merged['Affected Countries'] = df_merged['Location Name'].str.split(':').str[0]
In [15]:
geo_df = df_merged.dropna(subset=['Latitude', 'Longitude', 'Mag'], inplace=False)
color_scale_limits = [geo_df['Mag'].min(),geo_df['Mag'].max()]
geo_df = geo_df[geo_df['Date'].dt.year >= geo_df['Date'].max().year-50]

fig_map = px.scatter_geo(geo_df,
                         lat='Latitude',
                         lon='Longitude',
                         title='Distribuzione Geografica degli Eventi Sismici negli ultimi 50 anni',
                         labels={'Latitude': 'Latitudine', 'Longitude': 'Longitudine'},
                         hover_name='Location Name',
                         animation_frame=geo_df['Date'].dt.year,
                         color='Mag',
                         color_continuous_scale=px.colors.sequential.Reds,
                         range_color=color_scale_limits)

fig_map.update_geos(projection_type="natural earth")
fig_map.update_coloraxes(colorbar=dict(title='Magnitudine'))
fig_map.update_layout(width=1000, height=600)
fig_map.show()

Magnitudine media¶

Abbiamo deciso di rappresentare tramite un scala di colori il magnitudo presente nelle varie nazioni. Ogni nazione nell'immagine viene colorata con una tonalità di blue che varia in base all'intensità del magnitudo. Un colore più chiaro indica un magnitudo basso mentre un blue scuro indica un magnitudo alto.

In [16]:
countries_list = df_merged['Affected Countries'].str.split('; ', expand=True).stack().reset_index(level=1, drop=True).rename('AffCountry')
df_split = df_merged.drop('Affected Countries', axis=1).join(countries_list)

# Calcolo della media delle magnitudini per ogni paese
df_avg_mag = df_split.groupby('AffCountry')['Mag'].mean().reset_index()

# Creazione del grafico choropleth
fig = px.choropleth(df_avg_mag, 
                    locations='AffCountry',
                    locationmode='country names',
                    color='Mag',
                    title='Magnitudine media per Paese',
                    color_continuous_scale=px.colors.sequential.Blues)

fig.update_coloraxes(colorbar=dict(title='Magnitudine Media'))
fig.update_layout(height=600, width=1000)
fig.show()

Osservazione delle dieci magnitudini nei paesi più colpiti¶

L'analisi corrente si propone di esaminare le magnitudini negli stati più gravemente colpiti mediante l'utilizzo di un BoxPlot. Ciascun "box" nel diagramma rappresenta la distribuzione delle magnitudini relative agli eventi sismici in uno specifico paese. Le linee che si estendono dai box indicano la dispersione delle magnitudini degli eventi sismici, evidenziando eventuali valori estremi o "outlier".

Il confronto tra i box e le relative annotazioni agevola l'identificazione di distribuzioni di magnitudine più focalizzate o diffuse. Paesi caratterizzati da "whiskers" più estese e mediana più elevata possono essere interpretati come regioni con una variabilità maggiore e magnitudini medie più elevate degli eventi sismici.

In [17]:
conteggio_paesi = df_merged['Affected Countries'].value_counts().reset_index()
conteggio_paesi.columns = ['Paese', 'Numero Terremoti']

top_10_paesi = conteggio_paesi.head(10)['Paese'].tolist()

df_top_10 = df_merged[df_merged['Affected Countries'].isin(top_10_paesi)].copy()
df_top_10['Affected Countries'] = pd.Categorical(df_top_10['Affected Countries'], categories=top_10_paesi, ordered=True)
df_top_10 = df_top_10.sort_values(by='Affected Countries')

fig = px.box(df_top_10, x='Affected Countries', y='Mag', title='Box Plot delle Magnitudini dei 10 Paesi più colpiti',
             category_orders={'Affected Countries': top_10_paesi})
for i, row in conteggio_paesi.iterrows():
    if row['Paese'] in top_10_paesi:
        fig.add_annotation(x=row['Paese'], y=df_top_10['Mag'].min()-1,
                           text=row["Numero Terremoti"],
                           showarrow=False, font=dict(size=13))
fig.update_yaxes(range=[df_top_10['Mag'].min()-1.5, len(top_10_paesi)])
fig.update_layout(yaxis_title="Magnitudine", xaxis_title="10 Paesi più colpiti", height=800, width=1100,
    xaxis=dict(showline=True, linewidth=2, linecolor='black'),
    yaxis=dict(showline=True, linewidth=2, linecolor='black'))
fig.show()

Magnitudini degli eventi sismici¶

Nel presente contesto, si procede con la generazione di un grafico di densità termica (heatmap) finalizzato a offrire un'illustrazione visiva della distribuzione temporale delle magnitudini relative agli eventi sismici, diligentemente catalogati nel DataFrame df_merged.

Attraverso l'impiego della libreria Plotly, è stato concretizzato un Heatmap in cui la variabile indipendente (asse delle ascisse, x) è dedicata all'anno di occorrenza degli eventi sismici, ricavato mediante l'estrazione dalla colonna 'Date'. Simultaneamente, la variabile dipendente (asse delle ordinate, y) rappresenta le magnitudini degli eventi sismici ('Mag'). A ulteriore impegno della rappresentazione grafica, sono stati introdotti istogrammi marginali sia lungo l'asse x che y, agevolando così l'osservazione approfondita delle distribuzioni marginali delle grandezze coinvolte nell'analisi.

In [18]:
fig = px.density_heatmap(df_merged,
                         x=df_merged['Date'].dt.year,
                         y='Mag',
                         marginal_x='histogram',
                         marginal_y='histogram',
                         title='Heatmap Temporale delle Magnitudini',
                         nbinsx=90, nbinsy=20)
fig.update_layout(
    xaxis=dict(range=[1897, datetime.now().year], showline=True, linewidth=2, linecolor='black'),
    yaxis=dict(range=[3, 9], showline=True, linewidth=2, linecolor='black'),
    yaxis_title="Magnitude",
    xaxis_title="Anno",
    height=500, width=1000
)

fig.update_coloraxes(colorbar=dict(title='Numero di terremoti'))
fig.show()

Analisi catastrofi naturali scaturite da terremoti¶

Il codice in esame si concentra sull'analisi della magnitudine media degli eventi sismici, tenendo conto delle circostanze specifiche in cui tali eventi si verificano. In particolare, si valuta la presenza di due condizioni distintive: la possibilità di tsunami (Tsu) e l'eventuale attività di eruzioni vulcaniche (Vol).

La descrizione dettagliata delle variabili calcolate è la seguente:

mag_mean_without_both: Questo valore rappresenta la magnitudine media degli eventi sismici che non sono associati né a condizioni di tsunami né a eruzioni vulcaniche. In altre parole, si tratta di una valutazione della magnitudine in situazioni in cui non sono verificate entrambe le condizioni contemporaneamente.

mag_mean_with_tsunami: Questo parametro indica la magnitudine media degli eventi sismici che si sono verificati in presenza di condizioni di tsunami. Si focalizza sull'analisi delle magnitudini specificamente correlate a eventi sismici che causano tsunami.

mag_mean_with_volcano: Questo valore rappresenta la magnitudine media degli eventi sismici che sono avvenuti in concomitanza con condizioni di eruzione vulcanica. Si concentra sull'analisi delle magnitudini degli eventi sismici che si verificano in presenza di attività vulcaniche.

In [19]:
mag_mean_without_both = df_merged['Mag'].mean()
mag_mean_with_tsunami = df_merged[df_merged['Tsu'].notnull()]['Mag'].mean()
mag_mean_with_volcano = df_merged[df_merged['Vol'].notnull()]['Mag'].mean()
mag_mean_with_both = df_merged[df_merged['Tsu'].notnull() & df_merged['Vol']]['Mag'].mean()

data = {'Tsunami': ['Without both', 'With Tsunami', 'With Volcano', 'With both'],
        'Average Magnitude': [mag_mean_without_both, mag_mean_with_tsunami, mag_mean_with_volcano, mag_mean_with_both]}
avg_mag_df = pd.DataFrame(data)
fig = px.bar(avg_mag_df, x='Tsunami', y='Average Magnitude',
             title='Magnitudine media dei terremoti che causano Tsunami o Eruzioni Vulcaniche',
             labels={'Average Magnitude': 'Magnitudine Media', 'Tsunami':'Codizioni Tsunami ed Eruzioni Vulcaniche'})

fig.update_layout(
    height=700, width=1000,
    xaxis=dict(showline=True, linewidth=2, linecolor='black'),
    yaxis=dict(showline=True, linewidth=2, linecolor='black'),
)

fig.show()

La correlazione tra terremoti, tsunami ed eruzioni vulcaniche può essere compresa attraverso meccanismi geologici interconnessi. Ad esempio, un terremoto può causare uno tsunami attraverso procedure che includono la subduzione delle placche tettoniche (sprofondamento di una zolla al di sotto di quella immediatamente adiacente). Durante la subduzione, la placca oceanica può essere spinta sotto un'altra placca, dando inizio a un terremoto sottomarino. Questo movimento può provocare aggiustamenti nel fondale marino, con conseguente formazione di un'onda di tsunami.

Inoltre, alcune eruzioni vulcaniche possono essere provocate da terremoti. Lo stress all'interno delle rocce e dei gas sotto il suolo terrestre può aumentare a causa dell'interesse sismico, provocando il rilascio di magma e un'eruzione vulcanica. In questo contesto, il passatempo sismico può fungere da catalizzatore per le tecniche vulcaniche.

In ogni caso, esiste una chiara interconnessione tra le forze geologiche che possono essere scatenate dagli eventi sismici, dando impulso a fenomeni quali tsunami ed eruzioni vulcaniche.

In [20]:
# Crea una nuova colonna 'Evento' basata sui valori in 'tsu' e 'vul'
df_pie = df_merged

df_pie['Event'] = df_pie.apply(lambda row: 'Entrambi' if (pd.notna(row['Tsu'])) and (pd.notna(row['Vol']))
else ('Tsunami' if pd.notna(row['Tsu'])
      else ('Eruzione vulcanica' if pd.notna(row['Vol']) > 0
            else 'Nessun evento')), axis=1)
# Creazione del grafico a torta
fig = px.pie(df_pie, names='Event', title='Distribuzione di Eventi Sismici che hanno causato Tsunami o Eruzioni Vulcaniche')
fig.update_traces(textinfo='percent', insidetextorientation='radial', textfont_size=16)
fig.update_layout(height=500, width=800, legend=dict(font=dict(size=16)))
fig.show()

Analisi profondità e magnitudine:¶

La mappa termica è suddivisa in bin, ciascuno dei quali rappresenta una combinazione di profondità e magnitudine degli eventi sismici. La scala cromatica di ciascun bin indica la densità di eventi sismici in quella specifica regione del grafico, dove regioni più rosse indicano un maggiore numero di eventi.

Per ottimizzare la visualizzazione, abbiamo apportato le seguenti personalizzazioni:

  • Limitato la visualizzazione della profondità tra 0 e 100 chilometri sull'asse verticale.
  • Limitato la visualizzazione della magnitudine tra 3.8 e 8.5 sull'asse orizzontale.
  • Fissato le dimensioni della visualizzazione a 1000 pixel di larghezza per 500 pixel di altezza.
In [21]:
fig = px.density_heatmap(df_merged, y='Focal Depth (km)', x='Mag',
                         title='Heatmap Relazione tra Profondità e Magnitudine',
                         labels={'Focal Depth (km)': 'Profondità', 'Mag': 'Magnitudine'},
                         color_continuous_scale=px.colors.sequential.Reds,
                         nbinsx=100, nbinsy=200)
fig.update_yaxes(range=[0,100])
fig.update_xaxes(range=[3.8,8.5])
fig.update_layout(
    xaxis=dict(showline=True, linewidth=2, linecolor='black'),
    yaxis=dict(showline=True, linewidth=2, linecolor='black'),
    width=1000, height=500)
fig.show()

Intensità scala Mercalli e magnitudo¶

Il codice esegue un'analisi sulla relazione tra la magnitudine degli eventi sismici e la loro intensità MMI (Modified Mercalli Intensity).

Inizialmente, vengono eliminati i dati che presentano valori mancanti nell'intensità MMI, generando un nuovo insieme di dati denominato "filtered_data".

Successivamente, i dati filtrati vengono raggruppati in base alla magnitudine degli eventi sismici, e viene calcolata la media dell'intensità MMI per ciascun gruppo. Questo processo crea un nuovo set di dati chiamato "grouped_data".

Successivamente, viene eseguita una regressione lineare sui dati raggruppati per identificare la tendenza nella relazione tra la magnitudine e l'intensità MMI. I coefficienti della regressione, ovvero la pendenza (slope) e l'intercetta (intercept), vengono calcolati.

Infine, viene creato un grafico a barre utilizzando Plotly Express che rappresenta la relazione tra la magnitudine e l'intensità MMI. Viene anche tracciata una linea di regressione sulla base dei coefficienti calcolati, evidenziando la tendenza generale della relazione. Il grafico fornisce un'indicazione visiva della correlazione tra questi due parametri sismici.

Scala Mercalli:¶

L'analisi considera la relazione tra due importanti parametri che caratterizzano gli eventi sismici: l'Intensità Mercalli Modificata (MMI) e la magnitudo. La magnitudo di un terremoto rappresenta la quantità totale di energia rilasciata durante l’evento sismico. È un valore numerico che aumenta all’aumentare dell’energia rilasciata. L’intensità MMI, invece, valuta l’impatto sismico su luoghi specifici. Misura gli effetti degli eventi sismici sulla superficie terrestre e sugli edifici. La scala MMI è divisa in categorie che vanno da I (impercettibile) a XII (distruzione totale).

Il codice esegue una regressione lineare tra magnitudo e intensità MMI per mostrare la tendenza generale di come la magnitudo di un terremoto può influenzare l'intensità percepita in determinate località.

In termini pratici, un terremoto di magnitudo maggiore tende ad avere effetti più intensi sulla superficie terrestre e sugli edifici, aumentando così il valore dell'intensità del MMI. È importante però notare che l’intensità percepita può variare a seconda della distanza dal punto di origine dell’evento sismico e della geologia locale.

In [22]:
filtered_data = df_merged.dropna(subset=['MMI Int'], inplace=False)
grouped_data = filtered_data.groupby('Mag')['MMI Int'].mean().reset_index()

x = grouped_data['Mag']
y = grouped_data['MMI Int']
coefficients = np.polyfit(x, y, 1)
slope, intercept = coefficients

fig = px.bar(grouped_data, x='Mag', y='MMI Int', title='Relazione tra intensità MMI e Magnitudine')

x_values = np.linspace(x.min(), x.max(), 100)
y_values = slope * x_values + intercept

fig.add_trace(go.Scatter(
    x=x_values,
    y=y_values,
    mode='lines',
    name='Regression Line',
    line=dict(color='red', dash='dot')
))
fig.update_layout(xaxis_title='Magnitudine', yaxis_title='Intensità MMI media', width=1000, height=500,
                  xaxis=dict(showline=True, linewidth=2, linecolor='black'),
                  yaxis=dict(showline=True, linewidth=2, linecolor='black'))
fig.update_xaxes(range=[grouped_data['Mag'].min()-.1, grouped_data['Mag'].max()+.1])
fig.show()

I dieci terremoti più¶

Per il seguente grafico abbiamo filtrato le righe del DataFrame df_merged per eliminare quelle che presentano dati mancanti nella magnitudo ('Mag') e nel nome della località ('Location Name'). Il risultato di questa operazione è memorizzato nel DataFrame "filtered_df".

Successivamente, il DataFrame filtrato viene ordinato in base alla magnitudo in ordine decrescente e vengono selezionate le prime 10 righe. Il nuovo DataFrame risultante è chiamato "top_10_df" e contiene le informazioni sui dieci terremoti più potenti.

Utilizzando la libreria Plotly Express, viene creato un grafico a barre in cui le località sono sull'asse delle ascisse (x) e le magnitudini sono sull'asse delle ordinate (y). Il titolo del grafico è "10 Terremoti più Potenti per Località", e sono state aggiunte etichette per chiarezza.

Per gestire le differenze di scala tra le magnitudini, l'asse delle ordinate è impostato con una scala logaritmica. Questo permette di visualizzare più chiaramente le differenze di magnitudo anche in presenza di un ampio intervallo di valori.

In [23]:
# Filtra righe con dati validi su Magnitude e Location Name
filtered_df = df_merged.dropna(subset=['Mag', 'Location Name'], inplace=False)

# Ordina il DataFrame in base alla magnitudo in ordine decrescente
top_10_df = filtered_df.sort_values(by='Mag', ascending=False).head(10)

# Crea il grafico a barre
fig = px.bar(top_10_df, x='Location Name', y='Mag',
             title='10 Terremoti più Potenti per Località',
             labels={'Mag': 'Magnitudine', 'Location Name': 'Località'})
# aggiunta della scala logaritmica sull'asse y per gestire le differenze di scala
fig.update_layout(yaxis_type='log', width=1100, height=800,
                  xaxis=dict(showline=True, linewidth=2, linecolor='black'),
                  yaxis=dict(showline=True, linewidth=2, linecolor='black'))

# Mostra il grafico
fig.show()

Terremoti letali¶

Abbiamo deciso di analizzare i 25 terremoti più letali. Abbiamo selezionato le colonne pertinenti ('Affected Countries' e 'Deaths') dal DataFrame df_merged e creato un nuovo DataFrame chiamato earthquake_data. Successivamente, raggruppa i dati in base ai paesi colpiti ('Affected Countries'), somma il numero di morti per ciascun paese e ordina i risultati in modo decrescente. I primi 25 paesi più letali sono quindi selezionati e memorizzati nel DataFrame top_25_deadliest.

In [24]:
# Select relevant columns
earthquake_data = df_merged[['Affected Countries', 'Deaths']]

# Group by location and sum the deaths for each location
grouped_data = earthquake_data.groupby('Affected Countries')['Deaths'].sum().reset_index()

# Sort the data by the number of deaths in descending order and take the top 25
top_25_deadliest = grouped_data.sort_values(by='Deaths', ascending=False).head(25)

# Create the horizontal bar chart using plotly.express
fig = px.bar(top_25_deadliest,
             y='Affected Countries',
             x='Deaths',
             orientation='h',
             title='I 25 terremoti più letali per paese colpito',
             labels={'Deaths': 'Numero di Morti', 'Affected Countries': 'Paese Colpito'},
             template='plotly',
             opacity=0.7)

fig.update_layout(width=1000, height=700,
                  xaxis=dict(showline=True, linewidth=2, linecolor='black'),
                  yaxis=dict(showline=True, linewidth=2, linecolor='black'))
# Show the graph
fig.show()

Analisi relazione tra profondità focale e magnitudine¶

In questo grafico, la profondità focale è sull'asse orizzontale (x), mentre la magnitudine è sull'asse verticale (y). Le dimensioni degli assi sono modificate specificando gli estremi e gli step desiderati. Infine, il layout del grafico viene personalizzato impostando uno sfondo nero per gli assi e specificando le dimensioni complessive del grafico.

Il risultato è visualizzato per fornire una rappresentazione visiva della relazione tra la profondità focale e la magnitudine degli eventi sismici.

In [25]:
# Seleziona le colonne necessarie per il grafico
data_for_plot = df_merged[['Mag', 'Focal Depth (km)']]

# Rimuovi righe con valori mancanti in una delle colonne
data_for_plot = data_for_plot.dropna()

# Crea il grafico con plotly.express invertendo gli assi
fig = px.scatter(data_for_plot, x='Focal Depth (km)', y='Mag',
                 title='Relazione tra Profondità Focale e Magnitudine',
                 labels={'Focal Depth (km)': 'Profondità Focale (km)', 'Mag': 'Magnitudine'})

# Imposta gli estremi e gli step degli assi
fig.update_yaxes(range=[data_for_plot['Mag'].min()-.2, data_for_plot['Mag'].max()+.2], dtick=1)
fig.update_xaxes(range=[-1, data_for_plot['Focal Depth (km)'].max()+10], dtick=100)
fig.update_layout(height=700, width=1000,
                 xaxis=dict(showline=True, linewidth=2, linecolor='black'),
                 yaxis=dict(showline=True, linewidth=2, linecolor='black')
)
# Mostra il grafico
fig.show()

Danni totali dei terremoti¶

Il grafico mostra l'andamento del danno totale dei terremoti nel corso degli anni, consentendo una rapida identificazione di eventuali tendenze o modelli. Attraverso questo grafico, è possibile identificare tendenze nel danno causato dai terremoti nel corso del tempo. Ad esempio, picchi notevoli potrebbero indicare anni con un numero significativo di terremoti di grande entità o potrebbe evidenziare periodi di intensa attività sismica. La sua natura interattiva consente agli utenti di esplorare più dettagliatamente il grafico e di ottenere informazioni specifiche su singoli punti o intervalli temporali.

In [26]:
earthquake_data = pd.DataFrame({
    'Total Damage ($Mil)': df_merged['Total Damage ($Mil)'],
    'Year': df_merged['Date'].dt.year
})

# Group by year and sum the total damages for each year
damages_per_year = earthquake_data.groupby('Year')['Total Damage ($Mil)'].sum().reset_index()

# Create a line plot using plotly.express
fig = px.line(damages_per_year, x='Year', y='Total Damage ($Mil)',
              title='Danni Totali dei terremoti ogni anno',
              labels={'Total Damage ($Mil)': 'Danni Totali (Milioni di $)', 'Year': 'Anno'},
              template='plotly')

fig.update_xaxes(range=[1970, damages_per_year['Year'].max()])
fig.update_yaxes(range=[0, damages_per_year['Total Damage ($Mil)'].max()])

fig.update_layout(height=700, width=1000,
                  xaxis=dict(showline=True, linewidth=2, linecolor='black'),
                  yaxis=dict(showline=True, linewidth=2, linecolor='black')
                  )

# Show the graph
fig.show()